﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data.OleDb;
using System.Data;



namespace GE_Database_Manager
{
	public class ADAPT : Database
	{
        //  string to file path
        private string _waveFormData;
        private string _kinematicData;
        private string _malfunctionData;
        private string _namePlateData;
        private string _key;
        private string _dataAttributes;
        private string _comments;
        private int progressStep;

        // the wrapper to insert into sql table
        private Standardized_Wrapper _wrapper;

        private enum STAGE { ONE, TWO, THREE };


        // constructor for Testing
        protected ADAPT()
        { 
        
        }

        public ADAPT(string waveFormData, string kinematicData, string malfunctionData, 
            string namePlateData,string dataAttributes,string comments)
        {
            _waveFormData = waveFormData;
            _kinematicData = kinematicData;
            _malfunctionData = malfunctionData;
            _namePlateData = namePlateData;
            _dataAttributes = dataAttributes;
            _comments = comments;
            
            // generate unique key
            _key = (_waveFormData + _kinematicData + _malfunctionData + _namePlateData + _dataAttributes + _comments);
        }

        public string DataAttributes 
        {
            get { return _dataAttributes;}
            set { } 
    
        }

        public string Comments 
        {
            get { return _comments; }
            set { }
        }
        
        public string WavFormData 
        { 
            get { return _waveFormData; }
            set {} 
        }

        public string KinematicData
        {
            get { return _kinematicData; }
            set {}
        }
        public string MalfunctionData
        {
            get { return _malfunctionData; }
            set {}
        }
        public string NamePlateData
        {
            get { return _namePlateData; }
            set {}
        }

        public override string Key 
        {
            get { return _key; } 
            set {} 
        }

        public override int ProgressStep 
        { 
          get {return progressStep;} 
          set {progressStep = value;} 
        }

		public override bool Process(Standardized_Wrapper wrapper)
		{

            try
            {
                // set the database name
                wrapper.CurrentDB = "ADAPT";

                // store the wrapper in the class
                this._wrapper = wrapper;

                passProgress(this, new System.ComponentModel.ProgressChangedEventArgs(progressStep, "ADAPT: Proccessing Machine Info.."));

                // grab the datatribues information
                Dictionary<String, String> dataAttr = this.proccessDataAttributes();

                // grab the pdf info
                Tuple<string, String> pdfInfo = this.ProcessPDF(_namePlateData);

                // read the excel info
                Dictionary<String, String> excelInfo = this.ProcessExcel(_kinematicData);

                // insert gearbox in to machine table
                String workOrder = (dataAttr.ContainsKey("work order")) ? dataAttr["work order"] : String.Empty;
                String gearboxMake = (dataAttr.ContainsKey("gearbox_make")) ? excelInfo["gearbox_make"] : String.Empty;

                int machineId = _wrapper.InsertMachine(pdfInfo.Item1, "gearbox",
                    pdfInfo.Item2, null, workOrder, gearboxMake);

                // check if it failed to insert machine info
                if (machineId == -1) return false;

                passProgress(this, new System.ComponentModel.ProgressChangedEventArgs(progressStep, "ADAPT: Proccessing Stage Info.."));

                // insert the data into the stage table
                int stageID = insertStages(machineId, excelInfo);

                if (stageID == -1) return false;

                passProgress(this, new System.ComponentModel.ProgressChangedEventArgs(progressStep, "ADAPT: Proccessing Sensor Info.."));

                //insert sensor data into sensor table
                String pointName = dataAttr.ContainsKey("waveform point name") ? dataAttr["waveform point name"] : String.Empty; 
                int sensorId = _wrapper.InsertSensor(pointName, stageID);

                // check if if failed to insert data
                if (sensorId == -1) return false;

                passProgress(this, new System.ComponentModel.ProgressChangedEventArgs(progressStep, "ADAPT: Proccessing Engr Units.."));

                // insert into the engineering table
                String abv = dataAttr.ContainsKey("Engineering Units") ? dataAttr["Engineering Units"] : string.Empty;
                int engrUnitId = _wrapper.GetEngrUnitIdFromAbbreviation(abv);


                passProgress(this, new System.ComponentModel.ProgressChangedEventArgs(progressStep, "ADAPT: Processing WaveForm.."));

                // now lets insert all the waveforms from that waveform table, return start and end date
                String rate = dataAttr.ContainsKey("waveform sampling rate") ? dataAttr["waveform sampling rate"] : string.Empty;
                Tuple<DateTime, DateTime> date = insertWaveforms(sensorId, null,
                   Int32.Parse(rate), engrUnitId, null);

                // read the condition and comments
                string condition = ProcessMalfunctionTags(_malfunctionData);
                string comments = ProcessComments(_comments);

                passProgress(this, new System.ComponentModel.ProgressChangedEventArgs(progressStep, "ADAPT: Proccessing Machine Condition.."));

                // insert information into the machine condition table
                if (!_wrapper.InsertMachineCondition(machineId, date.Item1, date.Item2, condition, comments, "ADAPT"))
                    return false;
            }
             catch(Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
            }

            return true;
		}

        private int insertStages(int machineId,Dictionary<string,string> excelInfo)
        {
            // variable to store the stage id
            int[] stageIds = new int[3];

            try
            {
                // check if there is a first panetary stage
                if (excelInfo.ContainsKey("s1 type") && excelInfo["s1 type"].ToLower() == "planetary")
                {
                    stageIds[(int)STAGE.ONE] = insertPlanetaryStage(machineId, excelInfo["s1 fixed"],
                        excelInfo["s1 sun_tooth_count"], excelInfo["s1 planet_tooth_count"],
                            excelInfo["s1 ring_tooth_count"], excelInfo["s1 planet_count"]);
                }

                // check if there is a second parallel stage
                if (excelInfo.ContainsKey("s2 type") && excelInfo["s2 type"].ToLower() == "parallel")
                {
                    stageIds[(int)STAGE.TWO] = insertParalleStage(machineId, excelInfo["s2 gear_tooth_count"], excelInfo["s2 pinion_tooth_count"]);
                }
                // check if there is a third parallel stage
                if (excelInfo.ContainsKey("s3 type") && excelInfo["s3 type"].ToLower() == "parallel")
                {
                    stageIds[(int)STAGE.THREE] = insertParalleStage(machineId, excelInfo["s3 gear_tooth_count"], excelInfo["s3 pinion_tooth_count"]);
                }
            }
            catch 
            { 
                // lets catch any exceptions
                return -1;
            }
            return getStageID(stageIds);
        }

        private int getStageID(int[] stageIDs) {
            // return the correct sensor id based on the name
            if (_waveFormData.ToLower().Contains("sensor_1"))
            {
                return stageIDs[(int)STAGE.ONE];
            }
            if (_waveFormData.ToLower().Contains("sensor_2"))
            {
                return stageIDs[(int)STAGE.TWO];
            }
            if (_waveFormData.ToLower().Contains("sensor_3"))
            {
                return stageIDs[(int)STAGE.THREE];
            }
            return -1;
        }

        private int insertPlanetaryStage(int machineId, String fixedGear,String sun_tooth_count,String planet_tooth_count, String ring_tooth_count, 
            string planet_count)
        { 
            // check if ring or sun is fixed
            Fixed whatIsfixed = (fixedGear == "yes") ? Fixed.Ring : Fixed.Sun;

            // insert the first stage info
           int stageID = _wrapper.InsertStage(Designation.Planetary, machineId, whatIsfixed, null, null, Int32.Parse(sun_tooth_count),
                Int32.Parse(planet_tooth_count), Int32.Parse(ring_tooth_count),
                Int32.Parse(planet_count) );

           return stageID;
        }

        private int insertParalleStage(int machineId,String gear_tooth_count, String pinion_tooth_count) 
        {
            int stageID =_wrapper.InsertStage(Designation.Parallel, machineId, null,
                Int32.Parse(gear_tooth_count), Int32.Parse(pinion_tooth_count), null, null, null, null);

            return stageID;
        }

        public Tuple<DateTime, DateTime> insertWaveforms(int sensorID, float? machineRPM, int sampleRate, int engrUnitId, byte[] status)
        {
           
            // declare variables for starting and end date
            String startDate = null,date = null;
            float sample = 0.0f;
            // where to store the bytes
            List<byte> samples = new List<byte>();
            int bitsPerSample = 32;

            // open the csv file
            try
            {       
                // open file reader
                StreamReader file = new StreamReader(_waveFormData);
                
                // grab the first line
                string line = file.ReadLine(); 
                startDate = line.Split(',')[0];
                
                while ( line != null )
                {
                    // clear the list of bytes
                    samples.Clear();

                    // grab each line in the file
                    foreach (string val in line.Split(','))
                    {
                        // grab the date
                        if (val.ToUpper().Contains("AM") || val.ToUpper().Contains("PM"))
                        {
                            date = val;
                        }
                        // else grab data
                        else
                        {
                            if (val != String.Empty)
                            {
                                // convert to float, then get bytes
                                sample = Convert.ToSingle(val);
                                samples.AddRange(BitConverter.GetBytes(sample).ToList());
                            }
                        }
                    }
                    // insert info to waveform table
                    _wrapper.InsertWaveform(sensorID, Convert.ToDateTime(date), machineRPM, sampleRate, 
                        bitsPerSample, samples.ToArray(), engrUnitId, status);

                    // go to next line
                    line = file.ReadLine();
                }
  
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
            }

            return new Tuple<DateTime, DateTime>(Convert.ToDateTime(startDate), Convert.ToDateTime(date));

        }

        /// <summary>
        ///  This function proccess the data Attributes text file and stores it in a 
        ///  dictionary <key,value>  pair
        ///  key = attribute
        ///  value = value of attribute
        /// </summary>
        /// <returns></returns>
        protected Dictionary<string, string> proccessDataAttributes()
        {
            Dictionary<string, string> dataAttributesdict = new Dictionary<string, string>();
            int attrIndex;

            try
            {
                // read entire file line by line
                string[] dataAttributesStr = File.ReadAllLines(_dataAttributes);
             
                // get the waveform sampling rate, find the index in the array
                // then grab the value and store it in the dictionary
                attrIndex = Array.FindIndex(dataAttributesStr, s => s.ToLower().Contains("sampling") ||
                    s.ToLower().Contains("sampling rate") || s.ToLower().Contains("rate"));
                dataAttributesdict.Add("waveform sampling rate", dataAttributesStr[attrIndex].Split(':')[1].Trim());

                // get the waveform point name, find the index in the array
                // then grab the value and store it in the dictionary
                attrIndex = Array.FindIndex(dataAttributesStr, s => s.ToLower().Contains("point name")
                    || s.ToLower().Contains("point") || s.ToLower().Contains("name"));
                dataAttributesdict.Add("waveform point name", dataAttributesStr[attrIndex].Split(':')[1].Trim());

                // get the machine rpm, find the index in the array
                // then grab the value and store it in the dictionary
                attrIndex = Array.FindIndex(dataAttributesStr, s => s.ToLower().Contains("rpm"));
                dataAttributesdict.Add("machine RPM", dataAttributesStr[attrIndex].Split(':')[1].Trim());

                // get theengineering units, find the index in the array
                // then grab the value and store it in the dictionary
                attrIndex = Array.FindIndex(dataAttributesStr, s => s.ToLower().Contains("units"));
                dataAttributesdict.Add("Engineering Units", (dataAttributesStr[attrIndex].Split(':')[1].Trim()).Replace(";","/"));

                // get the waveform sampling rate, find the index in the array
                // then grab the value and store it in the dictionary
                attrIndex = Array.FindIndex(dataAttributesStr, s => s.ToLower().Contains("work order") ||
                    s.ToLower().Contains("work") || s.ToLower().Contains("order"));
                dataAttributesdict.Add("work order", dataAttributesStr[attrIndex].Split(':')[1].Trim());
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show(e.Message);
            }

            return dataAttributesdict;
        }


	}
}
